package code.whmmm.util.simple.sql;

import code.whmmm.util.simple.reflect.ReflectUtil;
import code.whmmm.util.hikari.jdbcpool.inter.SqlInterceptor;
import code.whmmm.util.simple.CodeStyleUtil;
import code.whmmm.util.simple.StrUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * <p><b>
 * 插入sql语句，工具类 <br/>
 * 目前仅测试了 mysql ，其他尚不支持！
 * </b></p>
 * <br/>
 * 创建时间: 2019/9/29 11:30
 *
 * @author Zero
 */
public class SqlInsertHelper {
    private SqlInsertHelper() {

    }

    private static final List<SqlInterceptor> interceptorList = new ArrayList<SqlInterceptor>(32);

    public static void addSqlInterceptor(SqlInterceptor interceptor){
        interceptorList.add(interceptor);
    }

    public static void addStringField(StringBuilder sb, Object v, String defaultValue) {
        if (v == null && defaultValue != null) {
            v = defaultValue;
        }
        if (defaultValue == null && v == null) {
            return;
        }
        sb.append("'").append(v.toString()).append("'");
    }

    /**
     * insert add values ('','') <br/>
     * 如果 v 是 null , 那么 返回 "".
     *
     * @param sb
     * @param v
     */
    public static void addStringField(StringBuilder sb, Object v) {
        addStringField(sb, v, "");
    }


    /**
     * 在末尾添加 ,
     *
     * @param sb {@link StringBuilder}
     * @param v  {@link Object}
     */
    public static void addStringFieldWithSeparator(StringBuilder sb, Object v) {
        addStringField(sb, v, "");
        sb.append(",");
    }

    /**
     * 添加 string 插入 语句
     *
     * @param sb
     * @param v
     */
    public static void addStr(StringBuilder sb, Object v) {
        addStringField(sb, v);
    }

    /**
     * 添加 string 插入 语句，同时结尾 插入 `,`
     *
     * @param sb
     * @param v
     */
    public static void addStrWith(StringBuilder sb, Object v) {
        addStringFieldWithSeparator(sb, v);
    }

    /**
     * 返回 sql 语句 ，将 list 添加到 insert sql 语句！<br/>
     * 如果 list 为 空 ，或者 list 元素都为空，则返回 null ！
     *
     * @param insertPrefix 例如: insert into xxxxxx values   |  注意此格式！！
     * @param list         要循环的列表
     * @param fileds       元素属性数组，根据反射获取此值。
     */
    public static <T> String insertBatch(String insertPrefix, Collection<T> list, String[] fileds) {
        if (list == null || list.size() == 0) {
            return null;
        }

        for (SqlInterceptor t : interceptorList) {
            list = t.doInsertHelperFilter(insertPrefix,list);
        }

        StringBuilder sb = new StringBuilder();

        T temp = null;

        Map<String, Field> fieldsMap = null;


        for (T t : list) {
            if (t == null) {
                continue;
            }

            if (temp == null) {
                temp = t;
                fieldsMap = ReflectUtil.getFieldsMap(temp);
            }


            if (sb.length() == 0) {
                sb.append("(");
            } else {
                sb.append(",(");
            }

            // 对 t 的属性赋值
            for (int i = 0; i < fileds.length; i++) {
                Object o = SqlUtil.getFieldValue(fieldsMap, fileds[i], t);

                if (i == (fileds.length - 1)) {
                    SqlInsertHelper.addStr(sb, o);
                } else {
                    SqlInsertHelper.addStrWith(sb, o);
                }
            }


            sb.append(")");
        }

        if (sb.length() > 0) {
            return insertPrefix + sb.toString();
        } else {
            return null;
        }

    }


    /**
     * 类似 {@link #insertBatch(String, Collection, String[])},<br/>
     * 请注意！本方法适用于 insert into 字段 和 sql 字段完全匹配的情况！
     *
     * @param insertPrefix ‘insert into table(字段名) values ’
     * @param list
     * @param isHump       sql字段是否是驼峰命名法。 insert into (字段1，字段2) values
     * @param <T>
     * @return
     */
    public static <T> String insertBatch(String insertPrefix, Collection<T> list, boolean isHump) {
        if (StrUtil.isBlank(insertPrefix) || list == null || list.size() == 0) {
            return null;
        }

        int start = insertPrefix.indexOf("(");
        int end = insertPrefix.lastIndexOf(")");


        String filedString = insertPrefix.substring(start + 1, end);

        String[] split = filedString.split(",");

        for (int i = 0; i < split.length; i++) {

            String s = split[i].trim();
            if (isHump) {
                s = CodeStyleUtil.lineToHump(s);
            }
            split[i] = s;
        }


        return insertBatch(insertPrefix, list, split);
    }

    /**
     * @param insertPrefix
     * @param list
     * @param <T>
     * @return
     * @see #insertBatch(String, Collection, boolean)
     */
    public static <T> String insertBatch(String insertPrefix, Collection<T> list) {
        return insertBatch(insertPrefix, list, false);
    }

    /**
     * 获取插入单条数据的 sql ！
     *
     * @param insertPrefix ‘insert into table(字段名) values ’
     * @param t
     * @param <T>
     * @return
     */
    public static <T> String insertOne(String insertPrefix, T t) {
        List<T> l = new ArrayList<T>();
        l.add(t);
        return insertBatch(insertPrefix, l);
    }

}
